﻿using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using LF.Common;
using LF.Shared.Dtos.Out;
using LF.Shared.Dtos.Input;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using System.Transactions;
using Org.BouncyCastle.Asn1.Ocsp;
using Serilog;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Utilities;
using LF.Application.Helpers;

namespace LF.Application.Helpers
{
    public class WeixinHelper
    {
        static string BaseUrl => "https://api.weixin.qq.com";

        /// <summary>
        /// 获取微信accesstoken
        /// </summary>
        /// <returns></returns>
        public static async Task<string?> GetAccessToken()
        {
            var config = LFConfig.Weixin;
            var result = await ApiHelper.GetAsync(BaseUrl, "cgi-bin/token", new Dictionary<string, object> {
                { "appid",config.AppId},
                { "secret",config.Secret},
                { "grant_type","client_credential"},
            });
            var accessToken = result!["access_token"]?.GetValue<string>();
            return accessToken;
        }

        /// <summary>
        /// 根据wx.lgoin的code获得手机号
        /// </summary>
        /// <param name="code">open-type getuserphonenumber=>code</param>
        /// <returns></returns>
        public static async Task<string?> GetPhoneAsync(string code)
        {
            var accessToken = await GetAccessToken();
            if (accessToken.IsNullOrEmpty())
                return string.Empty;
            var result = await ApiHelper.PostAsync(BaseUrl, "wxa/business/getuserphonenumber?access_token=" + accessToken, new Dictionary<string, object> {
                { "code",code}
            });
            var info = result!["phone_info"];
            if (info == null)
                return string.Empty;
            //用户绑定的手机号（国外手机号会有区号）
            var phoneNumber = info["phoneNumber"]?.GetValue<string>();
            //没有区号的手机号
            var purePhoneNumber = info["purePhoneNumber"]?.GetValue<string>();
            //区号
            var countryCode = info["countryCode"]?.GetValue<string>();
            return phoneNumber;
        }
        /// <summary>
        /// 获取openid
        /// </summary>
        /// <param name="loginCode">wx.login=>code</param>
        /// <returns></returns>
        public static async Task<string?> GetOpenidAsync(string loginCode)
        {
            var config = LFConfig.Weixin;
            var node = await ApiHelper.GetAsync(BaseUrl, "sns/jscode2session", new Dictionary<string, object> {
                { "appid",config.AppId},
                { "secret",config.Secret},
                { "js_code",loginCode},
                { "grant_type","authorization_code"},
            });
            var openid = node!["openid"]?.GetValue<string>();
            return openid;
        }

        #region pay
        /// <summary>
        /// 创建预支付订单<br/>
        /// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml<br/>
        /// https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_2.shtml#part-4
        /// </summary>
        /// <param name="openId">openid</param>
        /// <param name="orderNumber">订单编号</param>
        /// <param name="desc">订单描述</param>
        /// <param name="money">订单金额（分）</param>
        /// <returns>PrepayId 预支付订单号</returns>
        public static async Task<string> PayOrderAsync(string openId, string orderNumber, string desc,int money)
        {
            var config = LFConfig.WeixinPay;

            var client = GetWechatTenpayClient();

            /* 以 JSAPI 统一下单接口为例 */
            var request = new CreatePayTransactionJsapiRequest()
            {
                OutTradeNumber = orderNumber,
                AppId = LFConfig.Weixin.AppId,
                Description = desc,
                ExpireTime = DateTimeOffset.Now.AddMinutes(15),
                NotifyUrl = config.NotifyUrl,
                Amount = new CreatePayTransactionJsapiRequest.Types.Amount()
                {
                    Total = money
                },
                Payer = new CreatePayTransactionJsapiRequest.Types.Payer()
                {
                    OpenId = openId
                }
            };
            var response = await client.ExecuteCreatePayTransactionJsapiAsync(request);
            if (response.IsSuccessful())
            {
                return response.PrepayId;
            }
            else
            {
                Console.WriteLine("错误代码：" + response.ErrorCode);
                Console.WriteLine("错误描述：" + response.ErrorMessage);
            }
            return string.Empty;
        }
        /// <summary>
        /// 签名加密
        /// </summary>
        /// <param name="prepayId"></param>
        /// <returns></returns>

        public static IDictionary<string, string>? PaySign(string prepayId)
        {
            if (prepayId.IsNullOrEmpty()) return null;
            var client = GetWechatTenpayClient();
            return client.GenerateParametersForJsapiPayRequest(LFConfig.Weixin.AppId, prepayId);

        }

        static WechatTenpayClient _client = null;
        private static WechatTenpayClient GetWechatTenpayClient()
        {
            if (_client == null)
            {
                var config = LFConfig.WeixinPay;
                // 平台证书管理器的具体用法请参阅下文的基础用法与加密、验签有关的章节
                var manager = new InMemoryCertificateManager();
                var options = new WechatTenpayClientOptions()
                {
                    MerchantId = config.Id,
                    MerchantV3Secret = config.V3Secret,
                    MerchantCertificateSerialNumber = config.SerialNumber,
                    MerchantCertificatePrivateKey = config.PrivateKey,
                    PlatformCertificateManager = manager,
                    AutoEncryptRequestSensitiveProperty = true
                };
                _client = new WechatTenpayClient(options);
            }
            return _client;
        }

        /// <summary>
        /// 商户转账到用户
        /// </summary>
        /// <param name="openid">openid</param>
        /// <param name="money">金额</param>
        /// <returns>商家批次单号</returns>
        public static async Task<string> CashAsync(string openid, float money)
        {
            var config = LFConfig.Weixin;

            var client = GetWechatTenpayClient();
            var request = new CreateTransferBatchRequest
            {
                AppId = config.AppId,
                OutBatchNumber = AppUtil.GrgeneratedNumber2,
                BatchName = "积分提现",
                BatchRemark = "艾律特-提现",
                TotalAmount = (int)(money * 100),
                TotalNumber = 1,
                TransferDetailList = new List<CreateTransferBatchRequest.Types.TransferDetail>
                {
                   new CreateTransferBatchRequest.Types.TransferDetail
                   {
                       OutDetailNumber = AppUtil.GrgeneratedNumber2,
                       OpenId = openid,
                      TransferAmount = (int)(money * 100),
                      TransferRemark = "艾律特-提现"
                   }
                }
            };
            var response = await client.ExecuteCreateTransferBatchAsync(request);
            if (response.IsSuccessful())
            {
                return response.OutBatchNumber;
            }
            Console.WriteLine(response.ErrorCode + ":" + response.ErrorMessage);
            return string.Empty;
        }
        #endregion

        #region 小程序消息提醒

        /// <summary>
        /// 发送工单指派消息提醒（新增人员）
        /// </summary>
        /// <param name="openId">用户openid</param>
        /// <param name="workOrderNumber">工单编号</param>
        /// <param name="customerName">客户名称</param>
        /// <param name="workOrderType">工单类型</param>
        /// <param name="isResponsible">是否为负责人</param>
        /// <param name="workOrderId">工单ID，用于跳转详情</param>
        /// <returns></returns>
        public static async Task<bool> SendWorkOrderAssignNotifyAsync(string openId, string workOrderNumber, 
            string customerName, string workOrderType, bool isResponsible, string workOrderId)
        {
            try
            {
                var accessToken = await GetAccessToken();
                if (accessToken.IsNullOrEmpty())
                    return false;

                var role = isResponsible ? "负责人" : "协同人员";
                var data = new Dictionary<string, object>
                {
                    { "touser", openId },
                    { "template_id", "rRdkuWDEPQEYdO5pYsSSV3oHAMTtW4qAWB4tnGUwDBg" }, // 需要在配置中添加模板ID
                    { "page", $"pages/work-order/detail?id={workOrderId}" }, // 跳转到工单详情页
                    { "miniprogram_state", LFConfig.Weixin.Mode }, // 开发版为developer，体验版为trial，正式版为formal
                    { "data", new Dictionary<string, object>
                        {
                            { "thing1", new { value = workOrderNumber } }, // 工单编号
                            { "thing2", new { value = customerName.Length > 20 ? customerName.Substring(0, 20) : customerName } }, // 客户名称
                            { "thing3", new { value = workOrderType } }, // 工单类型
                            { "thing4", new { value = role } }, // 分配角色
                            { "time5", new { value = DateTime.Now.ToString("yyyy年MM月dd日 HH:mm") } } // 分配时间
                        }
                    }
                };

                var result = await ApiHelper.PostAsync(BaseUrl, "cgi-bin/message/subscribe/send?access_token=" + accessToken, data);
                
                if (result != null && result["errcode"]?.GetValue<int>() == 0)
                {
                    Log.Information($"工单指派消息发送成功，OpenId: {openId}, 工单号: {workOrderNumber}");
                    return true;
                }
                else
                {
                    var errcode = result?["errcode"]?.GetValue<int>() ?? -1;
                    var errmsg = result?["errmsg"]?.GetValue<string>() ?? "未知错误";
                    Log.Warning($"工单指派消息发送失败，OpenId: {openId}, 错误码: {errcode}, 错误信息: {errmsg}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, $"发送工单指派消息异常，OpenId: {openId}, 工单号: {workOrderNumber}");
                return false;
            }
        }

        /// <summary>
        /// 发送工单移除消息提醒（删除人员）
        /// </summary>
        /// <param name="openId">用户openid</param>
        /// <param name="workOrderNumber">工单编号</param>
        /// <param name="customerName">客户名称</param>
        /// <param name="workOrderType">工单类型</param>
        /// <param name="originalRole">原来的角色</param>
        /// <returns></returns>
        public static async Task<bool> SendWorkOrderRemoveNotifyAsync(string openId, string workOrderNumber, 
            string customerName, string workOrderType, string originalRole)
        {
            try
            {
                var accessToken = await GetAccessToken();
                if (accessToken.IsNullOrEmpty())
                    return false;

                var data = new Dictionary<string, object>
                {
                    { "touser", openId },
                    { "template_id", "STvDxs-DuO20hnPo9Y2IhQkgpWCs95_567TA_hBPxLc" }, // 需要在配置中添加模板ID
                    { "page", "pages/work-order/list" }, // 跳转到工单列表页
                    { "miniprogram_state", LFConfig.Weixin.Mode },
                    { "data", new Dictionary<string, object>
                        {
                            { "thing1", new { value = workOrderNumber } }, // 工单编号
                            { "thing2", new { value = customerName.Length > 20 ? customerName.Substring(0, 20) : customerName } }, // 客户名称
                            { "thing3", new { value = workOrderType } }, // 工单类型
                            { "thing4", new { value = $"已从{originalRole}中移除" } }, // 移除说明

                        }
                    }
                };

                var result = await ApiHelper.PostAsync(BaseUrl, "cgi-bin/message/subscribe/send?access_token=" + accessToken, data);
                
                if (result != null && result["errcode"]?.GetValue<int>() == 0)
                {
                    Log.Information($"工单移除消息发送成功，OpenId: {openId}, 工单号: {workOrderNumber}");
                    return true;
                }
                else
                {
                    var errcode = result?["errcode"]?.GetValue<int>() ?? -1;
                    var errmsg = result?["errmsg"]?.GetValue<string>() ?? "未知错误";
                    Log.Warning($"工单移除消息发送失败，OpenId: {openId}, 错误码: {errcode}, 错误信息: {errmsg}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex, $"发送工单移除消息异常，OpenId: {openId}, 工单号: {workOrderNumber}");
                return false;
            }
        }

        /// <summary>
        /// 批量发送工单指派消息
        /// </summary>
        /// <param name="assignNotifications">指派通知列表</param>
        /// <returns>成功发送的数量</returns>
        public static async Task<int> BatchSendWorkOrderAssignNotifyAsync(List<WorkOrderAssignNotification> assignNotifications)
        {
            int successCount = 0;
            
            foreach (var notification in assignNotifications)
            {
                var success = await SendWorkOrderAssignNotifyAsync(
                    notification.OpenId, 
                    notification.WorkOrderNumber, 
                    notification.CustomerName, 
                    notification.WorkOrderType, 
                    notification.IsResponsible, 
                    notification.WorkOrderId);
                
                if (success)
                {
                    successCount++;
                }
                
                // 避免频率限制，延迟100ms
                await Task.Delay(100);
            }
            
            return successCount;
        }

        /// <summary>
        /// 批量发送工单移除消息
        /// </summary>
        /// <param name="removeNotifications">移除通知列表</param>
        /// <returns>成功发送的数量</returns>
        public static async Task<int> BatchSendWorkOrderRemoveNotifyAsync(List<WorkOrderRemoveNotification> removeNotifications)
        {
            int successCount = 0;
            
            foreach (var notification in removeNotifications)
            {
                var success = await SendWorkOrderRemoveNotifyAsync(
                    notification.OpenId, 
                    notification.WorkOrderNumber, 
                    notification.CustomerName, 
                    notification.WorkOrderType, 
                    notification.OriginalRole);
                
                if (success)
                {
                    successCount++;
                }
                
                // 避免频率限制，延迟100ms
                await Task.Delay(100);
            }
            
            return successCount;
        }

        #endregion

        /// <summary>
        /// 获取太阳码
        /// 官方地址：https://developers.weixin.qq.com/minigame/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html
        /// </summary>
        /// <param name="scene">参数</param>
        /// <param name="page">页面地址</param>
        /// <param name="translate">是否透明</param>
        /// <param name="black">主题色是否为黑色，否为红色</param>
        /// <returns></returns>
        public static async Task<Stream?> GetQrCodeAsync(string page, string scene, bool translate = true,bool black = false)
        {
            var accessToken = await GetAccessToken();
            if (accessToken.IsNullOrEmpty())
                return null;
            var result = await ApiHelper.Post2Async(BaseUrl, "wxa/getwxacodeunlimit?access_token=" + accessToken, new Dictionary<string, object> {
                { "scene", scene },
                { "page",$"pages/{page}"},
                { "check_path",false },
                { "auto_color",false},
                { "line_color",black?new {r=0,g=0,b=0}:new {r=255,g=0,b=0}},
                { "is_hyaline",translate},
                {"env_version",LFConfig.Weixin.Mode }
            });
            result?.Seek(0, SeekOrigin.Begin);
            return result;
        }

      
        /// <summary>
        /// 支付回调
        /// 参考地址 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_5.shtml
        /// </summary>
        /// <param name="callback"></param>
        /// <param name="callbackJson"></param>
        /// <returns>订单编号</returns>
        public static async Task<string> PayCallBack(PayCallbackInput callback,string callbackJson)
        {
            await Task.Delay(1);


            var client = GetWechatTenpayClient();
            /*var c1 = "1727073609";
            var c2 = "nJESoDBAwyIXgaz4X6wRmJTkRnio5SQL";
            var c3 = "UmL8X4DcB+ZxKaLd3/tV55kenFVW4oL4roPdpRts5lxREcJ3QOeOE7BJOjglllted6QTEzg3FGLs6rRkj0tNKNgx6qKrEGuGPmw7XT2j+jA2XX0XHopwv0imNgcjboDCPvcjSWq6g4km+NZ/ZfrttRqKCq3Fn16wrLoll15QiWWaaZBGhKIwVtvDQCZHk2D32l5Vh8wy+u7TBaARevv7Q6EJGlJKbxggml0VKkyJ9jL4+v2J5M4u6VxF9xCo1AosZ1ILRQZW1n3F8v8T1ovf/9Ajg9vG1WZcBqxLSBjLzGJumbIxMI0axQxooz91NBFvvEDc8maELBbsZqaqXgnVng==";
            var c4 = "2F3F987D3ECE235F013C4C10F3C05E4A21BF1D6B";
            var c31 = "WECHATPAY2-SHA256-RSA2048";

            callbackJson = "{\"id\":\"022b5f9c-f4ea-5867-a963-b95336f095ba\",\"create_time\":\"2024-09-23T14:40:09+08:00\",\"resource_type\":\"encrypt-resource\",\"event_type\":\"TRANSACTION.SUCCESS\",\"summary\":\"支付成功\",\"resource\":{\"original_type\":\"transaction\",\"algorithm\":\"AEAD_AES_256_GCM\",\"ciphertext\":\"A6zoAJsKo0JDy/DWKg3yIjm+QDh0yLdwXHajM5HlKJaiEw5xV2RfkwksKNhttyMRq3oSa6l1NAKgW9vTXAtNo+6ayBHijzxLu750j6FIZemKCOuPf19niYbxvBE884/bwU3x3ACUxJLHbGESIoBC+MDdtd3H7kyHoMVabgK8qXg4gtLyhczVA9G2ebi0bVkUYhAWLFgrBQRwkBhdTAUS0BWgkTvjU2Xf9EdEbCHlj10WukOQaAX0CVOi/deBsJJeb1Di+68Qb7mV2g9xkuzbso6d1qKLM19gs2efHFfgojCCXgCmT/FHKXZGkEbaGdc3SBSFI+LQNIepdT1ZI3jZqgOfIk466uNfVGrYhyMMwOIa8bfWamdaX92JNbQO8zbSiw0AzDPSjYxflBTcc9AlO5q9IgiK7RS5fAlYMZB/82hsBcx3QyciUgUzSWpj2YdJDU0wrXalGyDhPbhMrzr7Hp5qZsyM5zaEJb10XRhrHp10z4pRD2mrlLOHc13Pi66FnhKh7nITX3PK06sT46WcZE8MfLNu8K9I6ITktWP1XYwm0fY+cZkj38LzQH5EoA==\",\"associated_data\":\"transaction\",\"nonce\":\"TzFlAYMXHeR6\"}}";
            //https://gitee.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat/blob/main/docs/WechatTenpayV3/Basic_RequestSensitiveDataEncryption.md
          
            //bool valid = client.VerifyEventSignature(callback.Timestamp, callback.Nonce, callbackJson, callback.Signature,callback.SignatureType,callback.SerialNumber);
            //Serilog.Log.Error(error, "错误");
            var request = new QueryCertificatesRequest();
            var response = await client.ExecuteQueryCertificatesAsync(request);
            if (response.IsSuccessful())
            {
                response = client.DecryptResponseSensitiveProperty(response);
                foreach (var certificateModel in response.CertificateList)
                {
                    client.PlatformCertificateManager.AddEntry(new CertificateEntry(certificateModel.EncryptCertificate.Algorithm, certificateModel.SerialNumber,certificateModel.EncryptCertificate.CipherText,certificateModel.EffectiveTime,certificateModel.ExpireTime));
                }
                Log.Information("查询微信商户平台证书成功。");
            }

            var s = await client.VerifyResponseSignatureAsync(c1, c2, callbackJson, c3, c4);
            if (!s.Result)
            {
                Log.Warning(s.Error, "错误");
            }*/



            var result = string.Empty;
            var webhookModel = client.DeserializeEvent(callbackJson);

            if ("TRANSACTION.SUCCESS".Equals(webhookModel.EventType))
            {
                /* 根据事件类型，解密得到支付通知敏感数据 */
                var webhookResource = client.DecryptEventResource<SKIT.FlurlHttpClient.Wechat.TenpayV3.Events.TransactionResource>(webhookModel);
                string outTradeNumber = webhookResource.OutTradeNumber;
                string transactionId = webhookResource.TransactionId;
                result = outTradeNumber;
            }

            return result;
        }
    }

    public class PayCallbackInput
    {
        public IHeaderDictionary Headers { get; set; } = null!;
        /// <summary>
        /// header Wechatpay-Timestamp
        /// </summary>
        public string Timestamp => Headers.GetOrDefault("Wechatpay-Timestamp").FirstOrDefault();
        /// <summary>
        /// header Wechatpay-Nonce
        /// </summary>
        public string Nonce => Headers.GetOrDefault("Wechatpay-Nonce").FirstOrDefault();
        /// <summary>
        /// header Wechatpay-Signature
        /// </summary>
        public string Signature => Headers.GetOrDefault("Wechatpay-Signature").FirstOrDefault();
        /// <summary>
        /// header Wechatpay-Signature-Type
        /// </summary>
        public string SignatureType => Headers.GetOrDefault("Wechatpay-Signature-Type").FirstOrDefault();
        /// <summary>
        /// header Wechatpay-Serial
        /// </summary>
        public string SerialNumber => Headers.GetOrDefault("Wechatpay-Serial").FirstOrDefault();
    }

    /// <summary>
    /// 工单指派通知对象
    /// </summary>
    public class WorkOrderAssignNotification
    {
        /// <summary>
        /// 用户OpenId
        /// </summary>
        public string OpenId { get; set; } = string.Empty;

        /// <summary>
        /// 工单编号
        /// </summary>
        public string WorkOrderNumber { get; set; } = string.Empty;

        /// <summary>
        /// 工单ID
        /// </summary>
        public string WorkOrderId { get; set; } = string.Empty;

        /// <summary>
        /// 客户名称
        /// </summary>
        public string CustomerName { get; set; } = string.Empty;

        /// <summary>
        /// 工单类型
        /// </summary>
        public string WorkOrderType { get; set; } = string.Empty;
        /// <summary>
        /// 工单标题
        /// </summary>
        public string Title { get; set; } = string.Empty;
        /// <summary>
        /// 是否为负责人
        /// </summary>
        public bool IsResponsible { get; set; }

        /// <summary>
        /// 用户ID
        /// </summary>
        public Guid UserId { get; set; }

        public string QyWeixinUserId { get; set; } = string.Empty;
    }

    /// <summary>
    /// 工单移除通知对象
    /// </summary>
    public class WorkOrderRemoveNotification
    {
        /// <summary>
        /// 用户OpenId
        /// </summary>
        public string OpenId { get; set; } = string.Empty;

        /// <summary>
        /// 工单编号
        /// </summary>
        public string WorkOrderNumber { get; set; } = string.Empty;

        /// <summary>
        /// 客户名称
        /// </summary>
        public string CustomerName { get; set; } = string.Empty;

        /// <summary>
        /// 工单类型
        /// </summary>
        public string WorkOrderType { get; set; } = string.Empty;

        /// <summary>
        /// 原来的角色
        /// </summary>
        public string OriginalRole { get; set; } = string.Empty;

        /// <summary>
        /// 用户ID
        /// </summary>
        public Guid UserId { get; set; }

        /// <summary>
        /// 工单标题
        /// </summary>
        public string Title { get; set; } = string.Empty;

        public string QyWeixinUserId { get; set; } = string.Empty;
    }
}
